home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 11587 / 11587.xpi / chrome / aviary.jar / content / browserOverlay.js < prev    next >
Text File  |  2009-10-16  |  40KB  |  1,183 lines

  1. /* Copyright (c) 2007-2009 Pearl Crescent, LLC.  All Rights Reserved. */
  2. /* vim: set sw=2 sts=2 ts=8 et syntax=javascript: */
  3.  
  4. var gAviaryMain =
  5. {
  6.   kExtensionID: "{d5eeb813-935a-435d-b01e-b3a02f2cb408}",
  7.   kLoginURLSuffix: "/login",
  8.   kLaunchAppURLSuffix: "/flash/aviary/index.aspx",
  9.   kLaunchFalconURLSuffix: "/launch/falcon",
  10.   kWelcomeURISuffix: "/tools/talon",
  11.   kNewVersionURISuffix: "/tools/talon?v=",
  12.   kToolbarItemID : "aviary-captureimageofpage",
  13.   kStatusbarItemID : "aviary-statusbar-capture",
  14.   kStatusbarID: "status-bar",
  15.   kNavBarID: "nav-bar",
  16.   kTBInitialInstallPref : "aviary.toolbar.initialinstallation",
  17.   kWarnIfNotLoggedInPref : "aviary.warnIfNotLoggedIn",
  18.   kTBItemLocationPref : "aviary.toolbarItem.location",
  19.   kLastVersionPref : "aviary.lastVersion",
  20.  
  21.   // These constants are also in options.xul
  22.   kPortionRegion:  0,
  23.   kPortionVisible: 1,
  24.   kPortionEntire:  2,
  25.  
  26.   // These constants are also in actionPrompt.xul
  27.   kActionNone: 0,
  28.   kActionSaveToAviary: 1,
  29.   kActionSaveAndOpen: 2,
  30.   kActionSaveToDesktop: 3,
  31.   kActionCopyToClipboard: 4,
  32.   kActionPrompt: 5,
  33.  
  34.   mAuthService: null,
  35.   mConnectService: null,
  36.   mPearlUtil: null,
  37.   mPreviousSearchEngine: null,
  38.  
  39.   LoginOrOut: function()
  40.   {
  41.     var isLoggedIn = false;
  42.     if (this.mAuthService)
  43.       isLoggedIn = this.mAuthService.isLoggedIn;
  44.  
  45.     if (isLoggedIn)
  46.       this.mAuthService.Logout();
  47.     else
  48.       this.OpenInNewTab(this.getLoginURL(), null);
  49.   },
  50.  
  51.   setLoginState: function(aIsLoggedIn)
  52.   {
  53.     var loginButton = document.getElementById("aviary-login");
  54.     var labelAttr = aIsLoggedIn ?  "aviaryLogoutLabel" : "aviaryLoginLabel";
  55.  
  56.     if (loginButton)
  57.     {
  58.       var s = loginButton.getAttribute(labelAttr);
  59.       loginButton.setAttribute("label", s);
  60.  
  61.       if (aIsLoggedIn)
  62.         loginButton.setAttribute("aviaryloggedin", aIsLoggedIn);
  63.       else
  64.         loginButton.removeAttribute("aviaryloggedin");
  65.     }
  66.  
  67.     this.mPearlUtil.SetElementAttribute("aviary-dashboard", "hidden",
  68.                                          !aIsLoggedIn);
  69.     this.mPearlUtil.SetElementAttribute("aviary-settings", "hidden",
  70.                                          !aIsLoggedIn);
  71.   },
  72.  
  73.   setToolsList: function(aToolList)
  74.   {
  75.     if (!aToolList && this.mAuthService)
  76.       aToolList = this.mAuthService.toolsList;
  77.  
  78.     // Only show top-level menu items for active tools.
  79.     gAviaryUtil.HideInactiveTools(aToolList);
  80.   },
  81.  
  82.   getLoginURL: function()
  83.   {
  84.     return this.mPearlUtil.GetASCIIPref("aviary.serverPrefix", "")
  85.            + this.kLoginURLSuffix;
  86.  
  87.   },
  88.  
  89.   LaunchAppByToolID: function(aToolID, aFileGUID, aImageURL, aImageInfo)
  90.   {
  91.     var serverPrefix = this.mPearlUtil.GetASCIIPref("aviary.serverPrefix", "");
  92.     if (!serverPrefix)
  93.       return;
  94.  
  95.     var urlParamInfo = {
  96.           1:  { urlParams: "tid=1&Phoenix" },
  97.           2:  { urlParams: "tid=2&Toucan" },
  98.           3:  { urlParams: "tid=3&Peacock" },
  99.           4:  { urlParams: "tid=4&Raven" },
  100.           5:  { urlParams: "tid=5&Hummingbird" },
  101.           6:  { urlParams: "tid=6&Myna" },
  102.           14: { urlParams: "tid=14&Woodpecker" }};
  103.  
  104.     var url = serverPrefix;
  105.     var infoObj = urlParamInfo[aToolID];
  106.     if (!infoObj)
  107.       url += this.kLaunchFalconURLSuffix;  // Launch Falcon (tid=20) by default.
  108.     else
  109.     {
  110.       url += this.kLaunchAppURLSuffix;
  111.       url = this.appendURLParam(url, infoObj.urlParams);
  112.     }
  113.  
  114.     if (aFileGUID)
  115.       url = this.appendURLParam(url, "fguid=" + encodeURIComponent(aFileGUID));
  116.     if (aImageURL)
  117.       url = this.appendURLParam(url, "url=" + encodeURIComponent(aImageURL));
  118.     if (aImageInfo)
  119.     {
  120.       if (aImageInfo.id)
  121.         url = this.appendURLParam(url, "imageid=" + aImageInfo.id);
  122.       if (aImageInfo.width && aImageInfo.height)
  123.       {
  124.         url = this.appendURLParam(url, "width=" + aImageInfo.width);
  125.         url = this.appendURLParam(url, "height=" + aImageInfo.height);
  126.       }
  127.     }
  128.  
  129.     var params = "fullscreen=yes,resizable=yes,menubar=no,location=no,status=no,toolbar=no";
  130.     // TODO: use GUID for window name when appropriate; bring to front, etc.
  131.     var win = window.open(url, 'x', params);
  132.   },
  133.  
  134.   appendURLParam: function(aURL, aEncodedParam)
  135.   {
  136.     if (!aURL || !aEncodedParam)
  137.       return aURL;
  138.  
  139.     aURL += (aURL.indexOf('?') < 0) ?  '?' : '&';
  140.     return aURL + aEncodedParam;
  141.   },
  142.  
  143.   LaunchApp: function(aTBItem)
  144.   {
  145.     if (!aTBItem)
  146.       return;
  147.  
  148.     var toolID = aTBItem.getAttribute("aviary-tid");
  149.     this.LaunchAppByToolID(toolID, null, null, null);
  150.   },
  151.  
  152.   OpenURLFromMenu: function(aMenuItem, aEvent)
  153.   {
  154.     if (!aMenuItem)
  155.       return;
  156.  
  157.     this.OpenURL(aMenuItem.getAttribute("url"), aEvent, true);
  158.   },
  159.  
  160.   OpenTalonOptions: function()
  161.   {
  162.     this.mPearlUtil.OpenPrefsWindow("aviary:prefs",
  163.                                     "chrome://aviary/content/options.xul");
  164.   },
  165.  
  166.   CaptureDefault: function()
  167.   {
  168.     var pagePortion = this.mPearlUtil.GetIntPref("aviary.defaultCaptureType",
  169.                                                  this.kPortionRegion);
  170.     if (this.kPortionRegion == pagePortion)
  171.       this.CaptureRegion();
  172.     else
  173.       this.CaptureImageOfPage(pagePortion, this.kActionPrompt);
  174.   },
  175.  
  176.   CaptureRegion: function()
  177.   {
  178.     var isLoggedIn = this.mAuthService.isLoggedIn;
  179.     if (!isLoggedIn && this.promptToLogin(true))
  180.       return;
  181.  
  182.     var win = this.mPearlUtil.GetTopBrowserWindow();
  183.     var r = {};
  184.     r.startX = win.pageXOffset;
  185.     r.startY = win.pageYOffset;
  186.     r.pageW = this.mPearlUtil.GetWindowWidth(win, false);
  187.     r.pageH = this.mPearlUtil.GetWindowHeight(win, false);
  188.     var reminderElem = document.getElementById("AviaryDragReminder");
  189.     if (reminderElem)
  190.     {
  191.       if (r.pageW > 80)
  192.         reminderElem.style.maxWidth = (r.pageW - 40) + "px";
  193.       else
  194.         reminderElem.style.maxWidth = r.pageW + "px";
  195.       reminderElem.style.display = "block";
  196.       if (r.pageH > 120 && r.pageW > 300) // heuristic
  197.         reminderElem.style.marginTop = "40px";
  198.       else
  199.         reminderElem.style.marginTop = "0px";
  200.  
  201.       var popupElem = document.getElementById("AviarySelectionPopup");
  202.       if (popupElem)
  203.       {
  204.         var mouseDownListener = function(aEvent)
  205.           {
  206.             reminderElem.style.display = "none";
  207.             popupElem.removeEventListener("mousedown", mouseDownListener, true);
  208.           };
  209.         popupElem.addEventListener("mousedown", mouseDownListener, true);
  210.       }
  211.     }
  212.     com.aviary.talon.grab.init(win, r, null, 0, true,
  213.                                this.RegionCaptureCallback, null);
  214.   },
  215.  
  216.   // aAction is ignored if aPagePortion == gAviaryMain.kPortionRegion.
  217.   // Otherwise, aAction should be one of the gAviaryMain.kAction constants.
  218.   CaptureImageOfPage: function(aPagePortion, aAction)
  219.   {
  220.     if (this.kPortionRegion != aPagePortion && !this.mAuthService.isLoggedIn)
  221.     {
  222.       var actionIsSave = (this.kActionSaveToAviary == aAction);
  223.       if (actionIsSave || this.kActionPrompt == aAction)
  224.       {
  225.         var didOpenLoginPage = this.promptToLogin(!actionIsSave);
  226.         if (actionIsSave || didOpenLoginPage)
  227.           return;
  228.       }
  229.     }
  230.  
  231.     var win = this.mPearlUtil.GetTopBrowserWindow();
  232.     this.captureAndUploadImage(win, null, aPagePortion, null, aAction);
  233.   },
  234.  
  235.   RegionCaptureCallback: function(aBrowserWin, aRegionRect, aArg, aDoCancel)
  236.   {
  237.     if (aBrowserWin && aRegionRect && !aDoCancel)
  238.     {
  239.       gAviaryMain.captureAndUploadImage(aBrowserWin, null,
  240.                                         gAviaryMain.kPortionRegion,
  241.                                         aRegionRect, gAviaryMain.kActionPrompt);
  242.     }
  243.   },
  244.  
  245.   // If aImageNode is null, the background image is used.
  246.   EditImage: function(aImageNode)
  247.   {
  248.     // aImageNode.src and bgImageURL are always fully qualified URLs.
  249.     var imgURL = (aImageNode) ? aImageNode.src : gContextMenu.bgImageURL;
  250.     if (!imgURL)
  251.     {
  252.       if (aImageNode) // Must be a canvas; so try to upload and then edit it.
  253.         this.SaveImage(aImageNode, true);
  254.  
  255.       return;
  256.     }
  257.  
  258.     var tid = this.mPearlUtil.GetIntPref("aviary.defaultImageEditor", 20);
  259.     if (20 == tid) // Falcon
  260.     {
  261.       this.LaunchAppByToolID(tid, null, imgURL, null);
  262.       return;
  263.     }
  264.  
  265.     try
  266.     {
  267.       gAviaryUpload.UploadByURL(imgURL, tid);
  268.     }
  269.     catch (e) { dump(e + "\n"); } // TODO: improve error reporting.
  270.   },
  271.  
  272.   SaveImage: function(aImageNode, aDoUploadAndEdit)
  273.   {
  274.     if (!aImageNode)
  275.       return;
  276.  
  277.     if (!this.mAuthService.isLoggedIn)
  278.     {
  279.       this.promptToLogin(false);
  280.       return;
  281.     }
  282.  
  283.     var win = this.mPearlUtil.GetTopBrowserWindow();
  284.     var action = (aDoUploadAndEdit) ? this.kActionSaveAndOpen
  285.                                     : this.kActionSaveToAviary;
  286.     this.captureAndUploadImage(win, aImageNode, 0, null, action);
  287.   },
  288.  
  289.   SaveBGImage: function()
  290.   {
  291.     if (!this.mAuthService.isLoggedIn)
  292.     {
  293.       this.promptToLogin(false);
  294.       return;
  295.     }
  296.  
  297.     if (gContextMenu.bgImageURL) try
  298.     {
  299.       gAviaryUpload.UploadByURL(gContextMenu.bgImageURL, 0);
  300.     }
  301.     catch (e) { dump(e + "\n"); } // TODO: improve error reporting.
  302.   },
  303.  
  304.   // If aImageElement is null, the active page is captured.
  305.   // aPagePortion and aRegionRect affect active page captures.
  306.   captureAndUploadImage: function(aWin, aImageElement, aPagePortion,
  307.                                   aRegionRect, aAction)
  308.   {
  309.     if (this.kPortionRegion == aPagePortion && !aRegionRect)
  310.       aPagePortion = this.kPortionVisible;
  311.  
  312.     var progressMeter = new AviaryProgressMeter();
  313.     if (progressMeter)
  314.     {
  315.       progressMeter.SetIsCancelable(true);
  316.       var str = this.mPearlUtil.GetLocalizedString("CAPTURING_IMAGE");
  317.       progressMeter.SetLabel(str);
  318.     }
  319.  
  320.     // Use setTimeout() here so progress meter is rendered before we
  321.     // get inside slow functions like canvas.drawWindow().
  322.     var self = this;
  323.     window.setTimeout(function() { self.captureAndUploadImage2(aWin, aImageElement, aPagePortion, aRegionRect, aAction, progressMeter) }, 0);
  324.   },
  325.  
  326.   captureAndUploadImage2: function(aWin, aImageElement, aPagePortion,
  327.                                    aRegionRect, aAction, aProgressMeter)
  328.   {
  329.     if (aAction == this.kActionPrompt)
  330.     {
  331.       // Display modal dialog to prompt for action.
  332.       var dlogflags = "chrome,titlebar,centerscreen,modal";
  333.       var paramObj = new Object();
  334.       paramObj.action = this.kActionNone;
  335.       paramObj.authService = this.mAuthService;
  336.       paramObj.loginURL = this.getLoginURL();
  337.       window.openDialog("chrome://aviary/content/actionPrompt.xul", "_blank",
  338.                         dlogflags, paramObj);
  339.       aAction = paramObj.action;
  340.     }
  341.  
  342.     if (aAction == this.kActionPrompt || aAction == this.kActionNone)
  343.     {
  344.       if (aProgressMeter)
  345.         aProgressMeter.Close(false, null);
  346.       return;
  347.     }
  348.  
  349.     // Attempt to get a file name from the image element or page title.
  350.     //    Also, get originating URL (page URL or image URL) for image captures.
  351.     var fname;
  352.     var origURL;
  353.  
  354.     if (this.kActionCopyToClipboard != aAction) try
  355.     {
  356.       // TODO: don't set fname if copying to clipboard.
  357.       if (this.kActionSaveToDesktop == aAction)
  358.       {
  359.         // Set fname to the page's domain if we are saving to the desktop.
  360.         if (aWin && aWin.document && aWin.document.location)
  361.         {
  362.           fname = aWin.document.location.hostname;
  363.           if (fname)
  364.           {
  365.             fname = fname.replace(/^www\./, '');
  366.             fname = fname.replace(/\./g, '-');
  367.           }
  368.         }
  369.       }
  370.       else if (aImageElement)
  371.       {
  372.         var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  373.                                 .getService(Components.interfaces.nsIIOService);
  374.         var imageURI = ioService.newURI(aImageElement.src, null, null);
  375.         var imageURL = imageURI.QueryInterface(Components.interfaces.nsIURL);
  376.         origURL = imageURL.spec;
  377.         fname = imageURL.fileName;
  378.         if (fname)
  379.         {
  380.           var dotIndex = fname.lastIndexOf('.');
  381.           if (dotIndex >= 0)
  382.             fname = fname.substring(0, dotIndex);
  383.  
  384.           fname += ".png";
  385.         }
  386.       }
  387.       else if (aWin && aWin.document)
  388.       {
  389.         origURL = aWin.document.location;
  390.         var docTitle = aWin.document.title;
  391.         if (docTitle)
  392.           docTitle = docTitle.replace(/[^\x20-\x7E]/g, ''); // Remove non-ASCII
  393.  
  394.         fname = this.mPearlUtil.SanitizeFileName(docTitle) + ".png";
  395.       }
  396.       // else fname = null;
  397.     } catch (e) {}
  398.  
  399.     try
  400.     {
  401.       var cpiObj = new AviaryCapturePageImage(aWin, aImageElement,
  402.                                               aPagePortion, aRegionRect);
  403.       var sizeObj = new Object;
  404.       cpiObj.DrawImageOnCanvas(sizeObj);
  405.  
  406.       var dataURI;
  407.       if (!aProgressMeter || !aProgressMeter.IsCanceled())
  408.         dataURI = cpiObj.GetPNGDataURI();
  409.  
  410.       cpiObj.Cleanup();
  411.  
  412.       if (aProgressMeter && aProgressMeter.IsCanceled())
  413.       {
  414.         aProgressMeter.Close(false, null);
  415.         return;
  416.       }
  417.  
  418.       // Use setTimeout() here so user has a chance to cancel.
  419.       var self = this;
  420.       window.setTimeout(
  421.           function()
  422.           {
  423.             self.captureAndUploadImage3(dataURI, sizeObj, fname, origURL,
  424.                                         aAction, aProgressMeter);
  425.           }, 0);
  426.     } catch (e) { dump(e + "\n"); } // TODO: improve error reporting.
  427.     // TODO: cleanup progress meter on error
  428.   },
  429.  
  430.   // Note: aName may be null.
  431.   captureAndUploadImage3: function(aDataURI, aSizeObj, aName, aOriginatingURL,
  432.                                    aAction, aProgressMeter)
  433.   {
  434.     try
  435.     {
  436.       if (this.mPearlUtil.GetBoolPref("aviary.showCapturedImageInTab", false))
  437.       {
  438.         this.OpenInNewTab(aDataURI, null);
  439.         if (aProgressMeter)
  440.           aProgressMeter.Close(false, null);
  441.  
  442.         return;
  443.       }
  444.  
  445.       if (aProgressMeter && aProgressMeter.IsCanceled())
  446.       {
  447.         aProgressMeter.Close(false, null);
  448.         return;
  449.       }
  450.  
  451.       if (this.kActionCopyToClipboard == aAction)
  452.       {
  453.         if (aProgressMeter)
  454.           aProgressMeter.SetIsCancelable(false); // too late to cancel now.
  455.  
  456.         var self = this;
  457.         var cbFunc = function(aDidSucceed)
  458.           {
  459.             self.ClipboardCopyCompleteCallback(aProgressMeter, aDidSucceed);
  460.           };
  461.  
  462.         com.aviary.talon.clipboard.CopyDataURIToClipboard(aDataURI, cbFunc);
  463.         return;
  464.       }
  465.  
  466.       var tid = this.mPearlUtil.GetIntPref("aviary.defaultImageEditor", 20); // Falcon
  467.       if ((20 == tid) && this.mConnectService
  468.           && (this.kActionSaveAndOpen == aAction))
  469.       {
  470.         // Register captured image with component to be pulled out later
  471.         // by Flash application.
  472.         var imageInfoObj = new Object;
  473.         imageInfoObj.id = this.mConnectService.addCapturedImage("image/png",
  474.                                                                 aDataURI);
  475.         if (aSizeObj)
  476.         {
  477.           imageInfoObj.width = aSizeObj.width;
  478.           imageInfoObj.height = aSizeObj.height;
  479.         }
  480.  
  481.         this.LaunchAppByToolID(tid, null, null, imageInfoObj);
  482.         if (aProgressMeter)
  483.           aProgressMeter.Close(false, null);
  484.         return;
  485.       }
  486.  
  487.       var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  488.                                 .getService(Components.interfaces.nsIIOService);
  489.       var uriObj = ioService.newURI(aDataURI, null, null);
  490.       var dataChannel = ioService.newChannelFromURI(uriObj);
  491.       var binStream = Components.classes["@mozilla.org/binaryinputstream;1"]
  492.                     .createInstance(Components.interfaces.nsIBinaryInputStream);
  493.       binStream.setInputStream(dataChannel.open());
  494.  
  495.       // Use setTimeout() here so user has a chance to cancel.
  496.       var self = this;
  497.       window.setTimeout(function() { self.captureAndUploadImage4(binStream, aName, aOriginatingURL, aAction, aProgressMeter); }, 150);
  498.     }
  499.     catch (e) { dump(e + "\n"); } // TODO: improve error reporting.
  500.     // TODO: clean up progress meter on error?
  501.   },
  502.  
  503.   // Note: this function is not used when copying to the clipboard.
  504.   captureAndUploadImage4: function(aImageStream, aName, aOriginatingURL,
  505.                                    aAction, aProgressMeter)
  506.   {
  507.     if (this.kActionSaveToDesktop == aAction)
  508.     {
  509.       this.promptAndSaveToFile(aImageStream, aName, aProgressMeter);
  510.     }
  511.     else try
  512.     {
  513.       var tid = 0;
  514.       if (this.kActionSaveAndOpen == aAction)
  515.         tid = this.mPearlUtil.GetIntPref("aviary.defaultImageEditor", 20); // Falcon
  516.       gAviaryUpload.UploadStream("image/png", aImageStream, aName,
  517.                                  aOriginatingURL, aProgressMeter, tid);
  518.     }
  519.     catch (e) { dump(e + "\n"); } // TODO: improve error reporting.
  520.  
  521.     // TODO: clean up progress meter on error?
  522.   },
  523.  
  524.   ClipboardCopyCompleteCallback: function(aProgressMeter, aDidSucceed)
  525.   {
  526.     if (aDidSucceed)
  527.     {
  528.       if (aProgressMeter)
  529.       {
  530.         aProgressMeter.SetValue(100);
  531.         aProgressMeter.Close(true, "IMAGE_COPIED"); // fade out
  532.       }
  533.     }
  534.     else
  535.     {
  536.       if (aProgressMeter)
  537.         aProgressMeter.Close(false, null);
  538.       var s = this.mPearlUtil.GetLocalizedString("ERROR_UNABLE_TO_COPY")
  539.       this.mPearlUtil.Alert(window, s);
  540.     }
  541.   },
  542.  
  543.   observe: function(aSubject, aTopic, aData)
  544.   {
  545.     if ("aviary:loginstatus" == aTopic)
  546.       this.setLoginState("true" == aData);
  547.     else if ("aviary:toolsavailable" == aTopic)
  548.       this.setToolsList(aData);
  549.     else if ("browser-search-engine-modified" == aTopic
  550.             && "engine-current" == aData)
  551.     {
  552.       var obsSvc = Components.classes["@mozilla.org/observer-service;1"]
  553.                          .getService(Components.interfaces.nsIObserverService);
  554.       obsSvc.removeObserver(this, aTopic);
  555.  
  556.       if (this.mPreviousSearchEngine)
  557.       {
  558.         var searchSvc =
  559.            Components.classes["@mozilla.org/browser/search-service;1"]
  560.                      .getService(Components.interfaces.nsIBrowserSearchService);
  561.         searchSvc.currentEngine = this.mPreviousSearchEngine;
  562.         this.mPreviousSearchEngine = null;
  563.       }
  564.     }
  565.     else if ("nsPref:changed" == aTopic)
  566.     {
  567.       if (this.kTBItemLocationPref == aData)
  568.       {
  569.         var newLoc = this.mPearlUtil.GetASCIIPref(this.kTBItemLocationPref);
  570.         var onStatusbar = (this.kStatusbarID == newLoc);
  571.         this.showToolbarItem(onStatusbar ? null : newLoc);
  572.         this.showStatusbarItem(onStatusbar);
  573.       }
  574.     }
  575.   },
  576.  
  577.   // Pass null for aToolbarID to remove item.
  578.   showToolbarItem: function(aToolbarID)
  579.   {
  580.     if (!aToolbarID)
  581.     {
  582.       this.removeToolbarItem();
  583.       return;
  584.     }
  585.  
  586.     var item = document.getElementById(this.kToolbarItemID);
  587.     if (item)
  588.     {
  589.       if (item.parentNode.id == aToolbarID)
  590.         return; // Already on correct toolbar.
  591.  
  592.       this.removeToolbarItem();  // On wrong toolbar.  Remove it.
  593.     }
  594.  
  595.     var toolbar = document.getElementById(aToolbarID);
  596.     if (!toolbar)
  597.     {
  598.       aToolbarID = this.kNavBarID;
  599.       toolbar = document.getElementById(aToolbarID);
  600.       if (!toolbar)
  601.         return; // Tried to fallback to navbar and failed.  Give up.
  602.     }
  603.  
  604.     var afterID = null;
  605.     if (this.kNavBarID == aToolbarID)
  606.     {
  607.       // On navbar, place "capture image" toolbar item after the home button.
  608.       var homeBtn = document.getElementById("home-button");
  609.       if (homeBtn && (homeBtn.parentNode == toolbar) && homeBtn.nextSibling)
  610.         afterID = homeBtn.nextSibling.id;
  611.     }
  612.  
  613.     this.prepareToCustomizeToolbox();
  614.     this.mPearlUtil.ShowToolbarItem(document, this.kToolbarItemID, afterID,
  615.                                     aToolbarID);
  616.     this.customizeToolboxDone();
  617.   },
  618.  
  619.   removeToolbarItem: function()
  620.   {
  621.     var item = document.getElementById(this.kToolbarItemID);
  622.     if (item)
  623.     {
  624.       var toolbar = item.parentNode;
  625.       var itemArray = toolbar.currentSet.split(',');
  626.       var itemFound = false;
  627.       for (var i = 0; !itemFound && (i < itemArray.length); ++i)
  628.       {
  629.         if (itemArray[i] == this.kToolbarItemID)
  630.         {
  631.           itemFound = true;
  632.           itemArray.splice(i, 1);  // remove from array
  633.         }
  634.       }
  635.  
  636.       if (itemFound)
  637.       {
  638.         this.prepareToCustomizeToolbox();
  639.         var cs = itemArray.join(',');
  640.         toolbar.setAttribute("currentset", cs);
  641.         toolbar.currentSet = cs;
  642.         document.persist(toolbar.id, "currentset");
  643.         this.customizeToolboxDone();
  644.       }
  645.     }
  646.   },
  647.  
  648.   prepareToCustomizeToolbox: function()
  649.   {
  650.     var splitter = document.getElementById("urlbar-search-splitter");
  651.     if (splitter)
  652.       splitter.parentNode.removeChild(splitter);
  653.   },
  654.  
  655.   // Re-init toolbars after a change was made, e.g., toolbar item added.
  656.   customizeToolboxDone: function()
  657.   {
  658.     try
  659.     {
  660.       BrowserToolboxCustomizeDone(true);
  661.     }
  662.     catch (e) {}
  663.   },
  664.  
  665.   showStatusbarItem: function(aDoShow)
  666.   {
  667.     this.mPearlUtil
  668.         .SetElementAttribute(this.kStatusbarItemID, "hidden", !aDoShow);
  669.   },
  670.  
  671.   OpenInNewTab: function(aURL, aEvent)
  672.   {
  673.     this.OpenURL(aURL, aEvent, true);
  674.   },
  675.  
  676.   OpenURL: function(aURL, aEvent, aInNewTab)
  677.   {
  678.     if (aURL)
  679.     {
  680.       var winToUse;
  681.       try
  682.       {
  683.         // If this is a popup window, find a non-popup one to use.
  684.         if (window.document.documentElement.getAttribute("chromehidden"))
  685.         {
  686.           const kWMClass = "@mozilla.org/appshell/window-mediator;1";
  687.           var wmSvc = Components.classes[kWMClass]
  688.                           .getService(Components.interfaces.nsIWindowMediator);
  689.           var winEnum = wmSvc.getZOrderDOMWindowEnumerator("navigator:browser",
  690.                                                            true);
  691.           while (!winToUse && winEnum.hasMoreElements())
  692.           {
  693.             var w = winEnum.getNext();
  694.             var chromeHidden = w.document.documentElement
  695.                                          .getAttribute("chromehidden");
  696.             if (!chromeHidden && w != window)
  697.               winToUse = w;
  698.           }
  699.         }
  700.       } catch (e) {}
  701.  
  702.       if (!winToUse)
  703.         winToUse = window;
  704.  
  705.       var tabBrowser = winToUse.top.getBrowser();
  706.       if (aInNewTab)
  707.       {
  708.         var newtab = winToUse.openNewTabWith(aURL, null, null, aEvent, false);
  709.         if (tabBrowser && newtab)
  710.           tabBrowser.selectedTab = newtab;
  711.       }
  712.       else if (tabBrowser)
  713.         tabBrowser.loadURI(aURL);
  714.     }
  715.   },
  716.  
  717.   onLoad: function()
  718.   {
  719.     this.mPearlUtil = com.aviary.talon.pearlutil;
  720.  
  721.     // Add hook so we can update the context menu when it is invoked.
  722.     var menu = document.getElementById("contentAreaContextMenu");
  723.     if (menu)
  724.     {
  725.       menu.addEventListener("popupshowing",
  726.                             this.onContextMenuShowing, false);
  727.     }
  728.  
  729.     // Remove outdated preference.
  730.     this.mPearlUtil.ClearUserPref("aviary.defaultEditor");
  731.  
  732.     // Add observers and initialize login state.
  733.     try
  734.     {
  735.       var obsSvc = Components.classes["@mozilla.org/observer-service;1"]
  736.                          .getService(Components.interfaces.nsIObserverService);
  737.       obsSvc.addObserver(this, "aviary:loginstatus", false);
  738.       obsSvc.addObserver(this, "aviary:toolsavailable", false);
  739.  
  740.       var prefSvc = this.mPearlUtil.mPrefService;
  741.       prefSvc.addObserver(this.kTBItemLocationPref, this, false);
  742.  
  743.       const kAuthServiceCID = "@aviary.com/aviary-auth;1";
  744.       this.mAuthService = Components.classes[kAuthServiceCID]
  745.                                 .getService(Components.interfaces.aviaryIAuth);
  746.       this.setLoginState(this.mAuthService.isLoggedIn);
  747.       this.setToolsList(null);
  748.  
  749.       const kConnectServiceCID = "@aviary.com/aviary-api;1";
  750.       this.mConnectService = Components.classes[kConnectServiceCID]
  751.                      .getService(Components.interfaces.aviaryIConnectInternal);
  752.     }
  753.     catch(e) {}
  754.  
  755.     // Show status bar item if pref says to do so.
  756.     var itemLoc = this.mPearlUtil.GetASCIIPref(this.kTBItemLocationPref);
  757.     this.showStatusbarItem(this.kStatusbarID == itemLoc);
  758.  
  759.     var self = this;
  760.     window.setTimeout(function() { self.DelayedInit(itemLoc); }, 0);
  761.   }, // onLoad()
  762.  
  763.   DelayedInit: function(aItemLocation)
  764.   {
  765.     // If first time we have been loaded, add toolbar items, etc.
  766.     var isFirstTime = this.mPearlUtil
  767.                           .GetBoolPref(this.kTBInitialInstallPref, true);
  768.     if (isFirstTime)
  769.     {
  770.       this.mPearlUtil.SetBoolPref(this.kTBInitialInstallPref, false);
  771.       this.OnFirstLoad(aItemLocation);
  772.     }
  773.  
  774.     // Display "Welcome" or "Upgrade" page in a new tab if appropriate:
  775.     var extVer;
  776.     try
  777.     {
  778.       var extMgr = Components.classes["@mozilla.org/extensions/manager;1"]
  779.                         .getService(Components.interfaces.nsIExtensionManager);
  780.       var extInfo = extMgr.getItemForID(this.kExtensionID);
  781.       extVer = extInfo.version;
  782.     } catch (e) {}
  783.  
  784.     var uriSuffix;
  785.     var lastVer = this.mPearlUtil.GetLocalizedStrPref(this.kLastVersionPref);
  786.     if (!lastVer && !isFirstTime)
  787.       lastVer = "0.8.7.1"; // or earlier, but close enough.
  788.     if (!lastVer)
  789.       uriSuffix = this.kWelcomeURISuffix;
  790.     else if (extVer && lastVer != extVer)
  791.       uriSuffix = this.kNewVersionURISuffix + extVer;
  792.  
  793.     if (uriSuffix)
  794.     {
  795.       var failedToWritePrefs = false;
  796.       if (extVer)
  797.       {
  798.         this.mPearlUtil.SetLocalizedStrPref(this.kLastVersionPref, extVer);
  799.         try
  800.         {
  801.           // Flush preferences file.  If it fails, do not open our page.
  802.           var prefS = Components.classes["@mozilla.org/preferences-service;1"]
  803.                              .getService(Components.interfaces.nsIPrefService);
  804.           prefS.savePrefFile(null);
  805.         }
  806.         catch(e)
  807.         {
  808.           failedToWritePrefs = true;
  809.         }
  810.       }
  811.  
  812.       if (!failedToWritePrefs)
  813.       {
  814.         var tabBrowser = top.getBrowser();
  815.         var serverPrefix = this.mPearlUtil.GetASCIIPref("aviary.serverPrefix");
  816.         if (tabBrowser && serverPrefix)
  817.         {
  818.           tabBrowser.loadOneTab(serverPrefix + uriSuffix, null, null, null,
  819.                                 false, false);
  820.         }
  821.       }
  822.     }
  823.   }, // DelayedInit()
  824.  
  825.   OnFirstLoad: function(aItemLocation)
  826.   {
  827.     if (aItemLocation && (this.kStatusbarID != aItemLocation))
  828.       this.showToolbarItem(aItemLocation);
  829.  
  830.     // Add Aviary search engine.
  831.     // TODO: do not add if already present, e.g., added via website.
  832.     try
  833.     {
  834.       var emSvc = Components.classes["@mozilla.org/extensions/manager;1"]
  835.                         .getService(Components.interfaces.nsIExtensionManager);
  836.       var fileLoc = emSvc.getInstallLocation(this.kExtensionID)
  837.                        .getItemLocation(this.kExtensionID);
  838.       fileLoc.append("defaults");
  839.       fileLoc.append("search.xml");
  840.  
  841.       var ioSvc = Components.classes["@mozilla.org/network/io-service;1"]
  842.                             .getService(Components.interfaces.nsIIOService);
  843.       var fileURI = ioSvc.newFileURI(fileLoc);
  844.       var searchSvc =
  845.            Components.classes["@mozilla.org/browser/search-service;1"]
  846.                      .getService(Components.interfaces.nsIBrowserSearchService);
  847.       this.mPreviousSearchEngine = searchSvc.currentEngine;
  848.       if (this.mPreviousSearchEngine)
  849.       {
  850.         var obsSvc = Components.classes["@mozilla.org/observer-service;1"]
  851.                          .getService(Components.interfaces.nsIObserverService);
  852.         obsSvc.addObserver(this, "browser-search-engine-modified", false);
  853.       }
  854.  
  855.       // NOTE: if the engine is already installed, this call has no effect.
  856.       // Also, addEngine() makes a copy of the xml file so to update we'll
  857.       // need to removeEngine() and then addEngine() again.
  858.       searchSvc.addEngine(fileURI.spec,
  859.                           Components.interfaces.nsISearchEngine.DATA_XML,
  860.                           null, false);
  861.     }
  862.     catch (e) {}
  863.   }, // OnFirstLoad()
  864.  
  865.   onContextMenuShowing: function()
  866.   {
  867.     if (gContextMenu)
  868.     {
  869.       var viewmenuitem = document.getElementById("context-viewimage");
  870.       var copymenuitem = document.getElementById("context-copyimage");
  871.       const kCI =  Components.interfaces;
  872.       var isAnImage = ((viewmenuitem && !viewmenuitem.hidden) ||
  873.                         (copymenuitem && !copymenuitem.hidden)) &&
  874.                 ((document.popupNode instanceof kCI.nsIDOMHTMLImageElement) ||
  875.                  (document.popupNode instanceof kCI.nsIDOMHTMLCanvasElement));
  876.       gContextMenu.showItem("aviary-editImage", isAnImage);
  877.       gContextMenu.showItem("aviary-editBGImage",
  878.                             !isAnImage && gContextMenu.hasBGImage);
  879.       gContextMenu.showItem("aviary-saveBGImage",
  880.                             !isAnImage && gContextMenu.hasBGImage);
  881.       gContextMenu.showItem("aviary-saveImage", isAnImage);
  882.       gContextMenu.showItem("aviary-editThisImage", isAnImage);
  883.       gContextMenu.showItem("aviary-editThisBGImage",
  884.                             !isAnImage && gContextMenu.hasBGImage);
  885.     }
  886.   },
  887.  
  888.   // returns true if login page was opened.
  889.   promptToLogin: function(aCanContinue)
  890.   {
  891.     if (aCanContinue &&
  892.         !this.mPearlUtil.GetBoolPref(this.kWarnIfNotLoggedInPref, true))
  893.     {
  894.       return false;
  895.     }
  896.  
  897.     const knsIPS = Components.interfaces.nsIPromptService;
  898.     var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  899.                        .getService(knsIPS);
  900.     var title = this.mPearlUtil.GetLocalizedString("ALERT_TITLE");
  901.  
  902.     var token = (aCanContinue) ? "NOT_LOGGED_IN_CONTINUE" : "NOT_LOGGED_IN";
  903.     var msg = this.mPearlUtil.GetLocalizedString(token);
  904.     var btn0Label = this.mPearlUtil.GetLocalizedString("LOGIN_BUTTON_LABEL");
  905.     var btn1Label = null;
  906.     var cbLabel = null;
  907.  
  908.     var flags = knsIPS.BUTTON_POS_0 * knsIPS.BUTTON_TITLE_IS_STRING
  909.                      + knsIPS.BUTTON_POS_0_DEFAULT;
  910.     if (aCanContinue)
  911.     {
  912.       flags += knsIPS.BUTTON_POS_1 * knsIPS.BUTTON_TITLE_IS_STRING;
  913.       btn1Label = this.mPearlUtil.GetLocalizedString("CONTINUE_BUTTON_LABEL");
  914.       cbLabel = this.mPearlUtil.GetLocalizedString("CONTINUE_CHECKBOX_LABEL");
  915.     }
  916.     else
  917.       flags += knsIPS.BUTTON_POS_1 * knsIPS.BUTTON_TITLE_CANCEL;
  918.  
  919.     var checkState = { value: false };
  920.     var rv = ps.confirmEx(window, title, msg, flags, btn0Label,
  921.                           btn1Label, null, cbLabel, checkState);
  922.     var doLogin = (0 == rv);
  923.     if (doLogin)
  924.       this.OpenInNewTab(this.getLoginURL(), null);
  925.  
  926.     if (checkState.value)
  927.       this.mPearlUtil.SetBoolPref(this.kWarnIfNotLoggedInPref, false);
  928.  
  929.     return doLogin;
  930.   },
  931.  
  932.   promptAndSaveToFile: function(aImageStream, aDomainName, aProgressMeter)
  933.   {
  934.     const kFileExt = ".png";
  935.     var baseName;
  936.     if (aDomainName)
  937.     {
  938.       baseName = this.mPearlUtil.GetFormattedLocalizedString(
  939.                                    "FILE_BASENAME_WITH_URL", [aDomainName], 1);
  940.       baseName = this.mPearlUtil.SanitizeFileName(baseName);
  941.     }
  942.     else
  943.       baseName = this.mPearlUtil.GetLocalizedString("FILE_BASENAME");
  944.  
  945.     var defaultLoc = this.mPearlUtil.GetFileLocation("Desk", baseName,
  946.                                                       kFileExt);
  947.     var prompt = this.mPearlUtil.GetLocalizedString("FILE_SAVE_PROMPT");
  948.     var filterName = this.mPearlUtil.GetLocalizedString("FILE_FILTERNAME")
  949.     var fileLoc = this.mPearlUtil.FilePickerSaveAs(prompt, filterName,
  950.                                                     kFileExt, defaultLoc);
  951.     var resultCode = 0;
  952.     if (fileLoc) // User chose a file (did not cancel).
  953.       resultCode = this.mPearlUtil.WriteStreamToFile(aImageStream, fileLoc);
  954.  
  955.     if (aProgressMeter)
  956.       aProgressMeter.Close(false, null);
  957.  
  958.     if (0 != resultCode)
  959.     {
  960.       var strName = "writeError";
  961.       const kFileErrorBase = 0x80520000;
  962.       switch (resultCode - kFileErrorBase)
  963.       {
  964.         /* We do not expect this error, and Mozilla's error message is odd.
  965.         case 8: // NS_ERROR_FILE_ALREADY_EXISTS
  966.           strName = "fileAlreadyExistsError";
  967.           break;
  968.         */
  969.         case 10: // NS_ERROR_FILE_DISK_FULL
  970.         case 16: // NS_ERROR_FILE_NO_DEVICE_SPACE
  971.           strName = "diskFull";
  972.           break;
  973.         case 17: // NS_ERROR_FILE_NAME_TOO_LONG
  974.           strName = "fileNameTooLongError";
  975.           break;
  976.         case 19: // NS_ERROR_FILE_READ_ONLY
  977.           strName = "readOnly";
  978.           break;
  979.         case 21: // NS_ERROR_FILE_ACCESS_DENIED
  980.           strName = "accessError";
  981.           break;
  982.       }
  983.  
  984.       const kBundle = "chrome://global/locale/nsWebBrowserPersist.properties";
  985.       var strBundle = Components.classes[this.mPearlUtil.kStringBundleCID]
  986.                             .getService(this.mPearlUtil.kStringBundleInterface)
  987.                             .createBundle(kBundle);
  988.  
  989.       var s = strBundle.formatStringFromName(strName, [fileLoc.leafName], 1);
  990.       this.mPearlUtil.Alert(window, s);
  991.     }
  992.   },
  993.  
  994.   endOfObject: true
  995. };
  996.  
  997. window.addEventListener("load", function() { gAviaryMain.onLoad(); }, false);
  998.  
  999. // Pass null for aImageElement to capture an image of the active web page.
  1000. // aPagePortion and aRegionRect affect active page captures.
  1001. function AviaryCapturePageImage(aWindow, aImageElement,
  1002.                                 aPagePortion, aRegionRect)
  1003. {
  1004.   this.init(aWindow, aImageElement, aPagePortion, aRegionRect);
  1005. }
  1006.  
  1007. AviaryCapturePageImage.prototype =
  1008. {
  1009.   mPearlUtil: null,
  1010.   mWindow: null,     // HTML Window
  1011.   mCanvasContainer: null,
  1012.   mCanvas: null,
  1013.   mImageElement: null,  // This remains null if capturing an entire web page.
  1014.   mPagePortion: 0,      // gAviaryMain.kPortionRegion, Visible, Entire.
  1015.   mRegionRect: null,    // Rectangular region to capture, if any.
  1016.   mSourceW: 0,          // Width of source page or image element.
  1017.   mSourceH: 0,          // Height of source page or image element.
  1018.   mSourceXOffset: 0,    // Horizontal offset within source page.
  1019.   mSourceYOffset: 0,    // Vertical offset within source page.
  1020.  
  1021.   init: function(aWindow, aImageElement, aPagePortion, aRegionRect)
  1022.   {
  1023.     if (!aWindow)
  1024.       this.onError("no window passed to Init"); // TODO: L10n
  1025.  
  1026.     var isRegionCapture = (gAviaryMain.kPortionRegion == aPagePortion);
  1027.     if ((isRegionCapture && !aRegionRect)
  1028.         || (!isRegionCapture && gAviaryMain.kPortionVisible != aPagePortion
  1029.             && gAviaryMain.kPortionEntire != aPagePortion))
  1030.     {
  1031.       this.onError("invalid page portion parameter"); // TODO: L10n
  1032.     }
  1033.  
  1034.     this.mPearlUtil = com.aviary.talon.pearlutil;
  1035.     this.mWindow = aWindow;
  1036.     this.mImageElement = aImageElement;
  1037.     this.mPagePortion = aPagePortion;
  1038.     if (isRegionCapture)
  1039.       this.mRegionRect = aRegionRect;
  1040.  
  1041.     var tbElem = document.getElementById("nav-bar");
  1042.     if (!tbElem)
  1043.       this.onError("did not find Navigation toolbar"); // TODO: L10n
  1044.  
  1045.     const kXULNameSpace = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  1046.     const kHTMLNameSpace = "http://www.w3.org/1999/xhtml";
  1047.     var sbElem = document.createElementNS(kXULNameSpace, "scrollbox");
  1048.     sbElem.setAttribute("width", 1);
  1049.     sbElem.setAttribute("height", 1);
  1050.     var canvasElem = document.createElementNS(kHTMLNameSpace, "canvas");
  1051.     canvasElem.setAttribute("style", "display:none");
  1052.     sbElem.appendChild(canvasElem);
  1053.     tbElem.appendChild(sbElem);
  1054.     this.mCanvasContainer = sbElem;
  1055.     this.mCanvas = canvasElem;
  1056.   },
  1057.  
  1058.   Cleanup: function()
  1059.   {
  1060.     this.mWindow = null;
  1061.     this.mImageElement = null;
  1062.     if (this.mCanvasContainer)
  1063.     {
  1064.       this.mCanvasContainer.parentNode.removeChild(this.mCanvasContainer);
  1065.       this.mCanvasContainer= null;
  1066.     }
  1067.   },
  1068.  
  1069.   DrawImageOnCanvas: function(aSizeObj)
  1070.   {
  1071.     try
  1072.     {
  1073.       var context = this.prepareCanvas();
  1074.       if (aSizeObj && this.mCanvas)
  1075.       {
  1076.         aSizeObj.width = this.mCanvas.width;
  1077.         aSizeObj.height = this.mCanvas.height;
  1078.       }
  1079.  
  1080.       if (this.mImageElement)
  1081.       {
  1082.         context.drawImage(this.mImageElement, 0, 0,
  1083.                           this.mSourceW, this.mSourceH);
  1084.       }
  1085.       else
  1086.       {
  1087.         var bgColor = "rgb(255,255,255)";
  1088.         if (!this.mPearlUtil.GetBoolPref("browser.display.use_system_colors",
  1089.                                          false))
  1090.         {
  1091.           bgColor = this.mPearlUtil.GetLocalizedStrPref(
  1092.                                    "browser.display.background_color", bgColor);
  1093.         }
  1094.  
  1095.         context.drawWindow(this.mWindow,
  1096.                            this.mSourceXOffset, this.mSourceYOffset,
  1097.                            this.mSourceW, this.mSourceH, bgColor);
  1098.       }
  1099.       context.restore();
  1100.     }
  1101.     catch (e)
  1102.     {
  1103.       this.onError("unable to capture image"); // TODO: L10n
  1104.     }
  1105.   },
  1106.  
  1107.   GetPNGDataURI: function()
  1108.   {
  1109.     if (!this.mCanvas)
  1110.       return null;
  1111.  
  1112.     return this.mCanvas.toDataURL("image/png");
  1113.   },
  1114.  
  1115.   // TODO: pass param with error? Components.results.NS_ERROR_INVALID_ARG
  1116.   onError: function(aErrorMsg)
  1117.   {
  1118.     throw new Components.Exception(aErrorMsg,
  1119.                                    Components.results.NS_ERROR_FAILURE);
  1120.   },
  1121.  
  1122.   // May throw.  Returns a 2d drawing context.
  1123.   // Callers should call context.restore() when done using the canvas.
  1124.   // This function also sets this.mSourceXOffset, this.mSourceYOffset,
  1125.   //    this.mSourceW, and this.mSourceH.
  1126.   prepareCanvas: function()
  1127.   {
  1128.     this.mCanvas.style.display = "inline"; // temporarily show the canvas.
  1129.  
  1130.     var zoomFactor = 1.0;
  1131.  
  1132.     this.mSourceW = 0;
  1133.     this.mSourceH = 0;
  1134.     this.mSourceXOffset = 0;
  1135.     this.mSourceYOffset = 0;
  1136.     if (this.mImageElement)
  1137.     {
  1138.       this.mSourceW = this.mImageElement.width;
  1139.       this.mSourceH = this.mImageElement.height;
  1140.     }
  1141.     else if (this.mRegionRect)
  1142.     {
  1143.       this.mSourceW = this.mRegionRect.pageW;
  1144.       this.mSourceH = this.mRegionRect.pageH;
  1145.       this.mSourceXOffset = this.mRegionRect.startX;
  1146.       this.mSourceYOffset = this.mRegionRect.startY;
  1147.     }
  1148.     else
  1149.     {
  1150.       var isEntirePage = (gAviaryMain.kPortionEntire == this.mPagePortion);
  1151.       this.mSourceW = this.mPearlUtil
  1152.                           .GetWindowWidth(this.mWindow, isEntirePage);
  1153.       this.mSourceH = this.mPearlUtil
  1154.                           .GetWindowHeight(this.mWindow, isEntirePage);
  1155.       if (!isEntirePage)
  1156.       {
  1157.         this.mSourceXOffset = this.mWindow.pageXOffset;
  1158.         this.mSourceYOffset = this.mWindow.pageYOffset;
  1159.       }
  1160.     }
  1161.  
  1162. // dump("sourceW: " + this.mSourceW + "; this.mSourceH: " + this.mSourceH + "\n");
  1163.     var canvasW = this.mSourceW * zoomFactor;
  1164.     var canvasH = this.mSourceH * zoomFactor;
  1165.  
  1166.     this.mCanvas.style.width = canvasW + "px";
  1167.     this.mCanvas.style.height = canvasH + "px";
  1168.     this.mCanvas.style.maxWidth = canvasW + "px";
  1169.     this.mCanvas.style.maxHeight = canvasH + "px";
  1170.     this.mCanvas.width = canvasW;
  1171.     this.mCanvas.height = canvasH;
  1172.  
  1173.     var context = this.mCanvas.getContext("2d");
  1174.     context.clearRect(0, 0, canvasW, canvasH);
  1175.     context.save();
  1176.     context.scale(zoomFactor, zoomFactor);
  1177.  
  1178.     return context;
  1179.   },
  1180.  
  1181.   endOfObject: true
  1182. };
  1183.